/*

METOO and MOIAUSSI! (C) Copyright Bill Buckels 1990 - 2008.
All rights reserved.
Apple //e ProDOS 8 Version 2.0

Written in Manx Aztec C65 Version 3.2b
MS-DOS cross-development environment

*/

/* root module */

#define CMAIN 1

#include "me2.h"

main()
{

   int position=0,oldposition=0,c,answers;

      /* set globals here */
      NOTE= (char *)&CURSORS[NOTE_OFFSET];
      NOTEBACK= (char *)&CURSORS[NOTEBACK_OFFSET];
      WORMBACK= (char *)&CURSORS[WORMBACK_OFFSET];
      LEFTWORM= (char *)&CURSORS[LWORM_OFFSET];
      RIGHTWORM= (char *)&CURSORS[RWORM_OFFSET];


   /* keep initialization stuff out of the way   */
   /* group our basic initialization stuff       */
   /* like setting the graphics mode and loading */
   /* the font set into CINIT.OVR                */

  ovloader("CINIT",GRAFMODE);

  RESTART:;

   /* load the auxmem (ems) libraries etc with the PLOGO.OVR overlay. */
   /* a key press is returned from PLOGO and if it is not    */
   /* the ESCAPE KEY we continue... otherwise we exit by     */
   /* calling CINIT.OVR to reset to text mode and exit.      */

   /* try to keep the main module as lean as possible    */
   /* but at the same time use the important functions   */
   /* that will be required by the module overlays to    */
   /* avoid making them any bigger than they need to be. */


   if(ovloader("PLOGO","ME2.RIB",ME2_SIZE)==ESCKEY)
      ovloader("CINIT",TEXTMODE);

   RECOVER:;

   /* put the menu screen into place */
   /* middle first */
   clearscreen();
   emsputimage(MENU_OFFSET,MENU_WIDTH,MENU_HEIGHT,0,79,PUT);
   emsputimage(MENUT_OFFSET,MENU_WIDTH,MENUT_HEIGHT,0,0,PUT);
   emsputimage(MENUB_OFFSET,MENU_WIDTH,MENUB_HEIGHT,0,110,PUT);

   multiples=3;

   /* set the startup flag and save the screen beneath position 0  */
   /* then put the first worm in place and move him based on the   */
   /* keys that are pressed or mouse position if installed.        */

   /* the main menu was moved into an overlay to conserve space    */

   /* BUT-  */
   /* somewhat of a time penalty is extracted in the extra DISK IO */
   /* required by the use of overlays. By updating the screens     */
   /* reasonably quickly and keeping our overlays small we can     */
   /* balance our real time sequencing to gloss this over.         */


   position=ovloader("MAINMENU",oldposition);
   oldposition=position;
   answers=0;

     do
     {


     switch(position)
     {
        /* load the overlays or restart the program    */
        /* we can do multiple overlays for each module */
        /* here... reward overlays... animation etc.   */

                  /* word spin and word match both return 20
                     since there is only 1 round of play
                     and then 1 reward and multiples
                     are always 3 and never advance to 6 */
        case 4 :  c=ovloader("ME24",answers);break;
        case 3 :  c=ovloader("ME23",answers);break;
                  /* word find and picture find have 2 rounds of play
                     in multiples of 3 and of 6 with a reward each time */
        case 2 :  c=ovloader("ME22",answers);break;
        case 1 :  c=ovloader("ME21",answers);break;
                  /* picture show */
        case 0 :  c=ovloader("ME20",answers);break; /* review - no reward */

        default:  goto RESTART;
        }

       answers=c;
       multiples=6;

       /* do the rewards */
       if(answers==10 || answers == 20)
       {
           if (position != 0) {
			   if(soundflag)ovloader("ME2R");
			   else wait();
		   }
       }
       /* end of round */
       if(answers==20 && position != 0)c=0;

    }while(c!=0);

    goto  RECOVER;

}


/* the functions below are intrinsic to this program and  */
/* some over-ride or replace library functions...         */
/* since they are called by all the modules they are kept */
/* in the ROOT SEGMENT                                    */

/* by putting noteworthy into the root with the sound function   */
/* and the putimage function, we avoid needing to load this code */
/* again... It is used by all modules...                         */

noteworthy(startflag)
int startflag;
{

    if(startflag) /* if we are starting a new menu then save */
    {             /* the area behind the note                */
     putimage(NOTEBACK,NOTE_WIDTH,NOTE_HEIGHT,NOTEX,NOTEY,GET);
    }
    else          /* if we are not just starting then toggle the sound */
    {
     /* make a tiny sound... */
     /* this gets the sound function into the root */
     sound(3,0,1);
     if(soundflag)soundflag=OFF;
     else soundflag=ON;
     }

    /* restore the screen behind the note if the soundflag is off */
    /* otherwise display the musical note.                        */

    if(!soundflag)
      putimage(NOTEBACK,NOTE_WIDTH,NOTE_HEIGHT,NOTEX,NOTEY,PUT);
    else
      putimage(NOTE,NOTE_WIDTH,NOTE_HEIGHT,NOTEX,NOTEY,P_AND);


}


randomchoice()
{
    /* return an answer within the range of questions */
    return randomseed[6]%multiples;
}

/* this version of gethc has a random value generator
   for gameplay and also returns a SPACE key value
   if the mouse button is down */
getch()
{
  char c;
  int idx, val;

            /* clear stragglers from the keyboard buffer */
            /* I duplicated the code in kbclear here to
               conserve the stack by avoiding a function call
               to kbclear */
            while((c=KEYPRESS[0]) > 127)
            {
                KEYCLEAR[0]=0;
                for (idx = 0;idx < 6; idx++){
					val = randomseed[idx] + 1;
					if (val > 81)val = 0;
					randomseed[idx] = val;
				}

                }
            /* read the keyboard buffer    */
            /* and return the character    */
            do{
                for (idx = 0;idx < 6; idx++){
					val = randomseed[idx] + 1;
					if (val > 81)val = 0;
					randomseed[idx] = val;
				}
                c = KEYPRESS[0];
                val = randomseed[6] + c;
                if (val > 32000)val = c;
                randomseed[6] = val;

                /* check for mouse button down
                   if no key in keyboard buffer */
                if (mouseflag == 0 && c < 128) {
                	cmouse();
                	if ((mousebutton>>7) == 1) {
				    	c =  32 + 128;
					}
				}

               }while(c < 128);

               c-=128;
               KEYCLEAR[0]=0;
               return (int )c;
}

kbhit()
{
  char c;
  int idx, val;

  /* read the keyboard buffer and the mouse */
  /* and return 0 if no character is waiting */

   c = KEYPRESS[0];
   if(c<128) {
	   if (mouseflag != 0)return 0;
	   cmouse();
	   if ((mousebutton>>7) != 1) return 0;
	   c =  32 + 128;
   }

	for (idx = 0;idx < 6; idx++){
		val = randomseed[idx] + 1;
		if (val > 81)val = 0;
		randomseed[idx] = val;
	}

	val = randomseed[6] + c;
	if (val > 32000)val = c;
	randomseed[6] = val;

   return (int)c-128;
}

kbclear()
{
  char c;
  int idx, val;

	while((c=KEYPRESS[0]) > 127)
	{
		KEYCLEAR[0]=0;
		for (idx = 0;idx < 6; idx++){
			val = randomseed[idx] + 1;
			if (val > 81)val = 0;
			randomseed[idx] = val;
		}

	}
}

waitkey(duration)
int duration;
{
	int c = 0, idx;

	for (idx = 0; idx < duration; idx++) {
	    sound(7,0,1);
	    c = kbhit();
		if (c!=0)break;
	}
	return c;

}

/* replace the library function with one of our own.
   in an effort to save memory. */
strlen(ptr)
char *ptr;
{
	int idx = 0;

	while(ptr[idx]!=0)idx++;

	return idx;
}


/* the screens in this program are
   composites of static and dynamic bitmaps.
   this was done in an effort to save disk space
   so a layout manager is required to put the
   pieces together. */
layout(number)
int number;
{
	clearscreen(); /* always clear the screen */

	switch(number) {

	   case 0: emsputimage(SHOW_OFFSET,SHOW_WIDTH,SHOW_HEIGHT,0,173,PUT);
	   case 1:
	   case 2:
	   emsputimage(MENU_OFFSET,MENU_WIDTH,MENU_HEIGHT,0,140,PUT);

	   if (multiples == 3) {
		  /* horizontal bars */
	      hbar(0,  0, BLUE,MENU_WIDTH,1);
	      hbar(61, 0, BLUE,MENU_WIDTH,1);
	      hbar(77, 0, WHITE,MENU_WIDTH,1);
	      hbar(78, 0, BLUE,MENU_WIDTH,61);
	      hbar(139,0, WHITE,MENU_WIDTH,1);

	   }
	   else {
	      hbar(0,  0, BLUE,MENU_WIDTH,1);
	      hbar(61, 0, BLUE,MENU_WIDTH,2);
	      hbar(123,0, BLUE,MENU_WIDTH,1);
		  hbar(139,0, WHITE,MENU_WIDTH,1);
	   }
	   break;
       case 3:
       emsputimage(SPIN_OFFSET,MENU_WIDTH,SPIN_HEIGHT,0,78,PUT);
       hbar(0,  0, BLUE,MENU_WIDTH,1);
	   hbar(61, 0, BLUE,MENU_WIDTH,1);
       hbar(77, 0, WHITE,MENU_WIDTH,1);
       break;
       case 4:
       hbar(0,  0, BLUE,MENU_WIDTH,1);
       hbar(161,0, BLUE,MENU_WIDTH,1);
       hbar(172,0, WHITE,MENU_WIDTH,1);
       break;


	}

}


/* load a minipic from our library
   into one of the 6 minipic buffers in auxmem */
loadmini(choice, position)
int choice, position;
{

   long lpos;
   unsigned buffer, lomem, himem;
   int fhrags;

   buffer = S0_OFFSET + (position * MINI_SIZE);

   lomem = 0x0C00+1096+24;
   himem=buffer+0x0C00;

   lpos = (long)MINI_SIZE * (long)choice;

   fhrags = open("RAG.RIB",O_RDONLY,0xc3);

   if (fhrags == -1)return -1;

   /* seek to the image */
   lseek(fhrags, lpos, 0);
   read(fhrags,(char *)lomem,MINI_SIZE);
   maintoaux(lomem,lomem+MINI_SIZE-1,himem);

   close(fhrags);

   return 0;

}

/* used by the first 4 modules
   to display a minipic from auxmem on the screen */
showmini(position, action, bufoff)
int position, action, bufoff;
{
	int buffer, x, y;

	buffer = S0_OFFSET + (bufoff * MINI_SIZE);

    x = picpos[position][0];
    y = picpos[position][1];

	emsputimage(buffer,MINI_WIDTH,MINI_HEIGHT,x,y,action);
}

/* used by all modules except the review module
   for tracking 1-10 correct answers */
shownumber(answers)
{
	int x, lomem, fhrags;
	long lpos;

	while (answers > 9)answers -= 10;

    lomem = 0x0C00+1096+24;

    lpos = (long) (N1_OFFSET + (answers * NUM_SIZE));

    fhrags = open("CURSORS.RIB",O_RDONLY,0xc3);

    if (fhrags == -1)return -1;
    /* seek to the image */
    lseek(fhrags, lpos, 0);
    read(fhrags,(char *)lomem,NUM_SIZE);
    close(fhrags);

    x = answers * NUM_WIDTH;

    putimage(lomem,NUM_WIDTH,NUM_HEIGHT,x,173,PUT);

	if(soundflag) {
		answers++;
    	for (x = 0; x < answers; x ++) {
			sound(4,x,1);
		}
	}

    return 0;


}

/* used by all modules except the sentence module
   which displays the picture and noun
   based on sentence length */
showtext(choice, erase)
int choice, erase;
{
   char buffer[NAM_LEN], arf[ARF_LEN];
   unsigned base;
   int x, y, l, a=0;


	if (multiples == 3)y = 66;
	else y = 128;

	if (erase) {
		hbar(y,0, BLACK,MENU_WIDTH,8);
	}
	else {

		base = NAM_OFFSET + (choice * NAM_LEN);
		emsget(base,&buffer[0],NAM_LEN);
		l = strlen(buffer);

		if (language == FRENCH) {
		   /* article prefix required for french */
		   base = ARF_OFFSET + (choice * ARF_LEN);
		   emsget(base,&arf[0],ARF_LEN);
		   for (a = 0; a < ARF_LEN;a++) {
		   	  if (arf[a] == '#')arf[a] = 0;
		   }
		   a = strlen(arf);

		}

		x = (39 -  l - a)/2;

		if (language == FRENCH) plots2(arf,x,y,1);

		plots2(buffer,x + a,y,1);
	}

}

/* mouse routines */

/* turn the mouse on */
mouseon()
{
    setmouseon();
    homemouse();
    readmouse();

}


/* read the mouse */
/* update the globals */
cmouse()
{
    unsigned char *ptr;

    readmouse();

	/* mouse status register */
	ptr=(unsigned char *)1916;
	mousebutton=0;
	mousebutton+=ptr[0];

	/* x coordinate - units = 0-1023 */
	mousex=0;
	ptr=(unsigned char *)1404; /* MSB */
	mousex +=ptr[0];
	mousex <<= 8;
	ptr=(unsigned char *)1148; /* LSB */
	mousex +=ptr[0];
	if(mousex>MXMAX)mousex=MXMAX;
	/* use 0-1023 horizontal units */


	/* y coordinate - units = 0-1023 */
	mousey=0;
	ptr=(unsigned char *)1532; /* MSB */
	mousey +=ptr[0];
	mousey <<= 8;
	ptr=(unsigned char *)1276; /* LSB */
	mousey +=ptr[0];
	if(mousey>MYMAX)mousey=MYMAX;
	/* use 0-1023 vertical units */


}


/* 6502 assembly language mouse core functions */
#asm

*
* use the second line of the second page of the text screen
* as a dynamic dispatch vector set pointing to the mouse routines
*

SETMOUSE   EQU $880
SERVEMOUSE EQU SETMOUSE+3
READMOUSE  EQU SETMOUSE+6
CLEARMOUSE EQU SETMOUSE+9
POSMOUSE   EQU SETMOUSE+12
CLAMPMOUSE EQU SETMOUSE+15
HOMEMOUSE  EQU SETMOUSE+18
INITMOUSE  EQU SETMOUSE+21

          public setmouseon_
setmouseon_
          lda  #$01
          ldx  #$C4
          ldy  #$40
          cli
          jsr  SETMOUSE
          rts


          public homemouse_

homemouse_
          ldx  #$C4
          ldy  #$40
          jsr  HOMEMOUSE
          rts

          public readmouse_
readmouse_
          ldx  #$C4
          ldy  #$40
          php
          sei
          jsr  READMOUSE
          cli
          plp
          rts


          public mouseoff_
mouseoff_

          lda  #$00
          ldx  #$C4
          ldy  #$40
          cli
          jsr  SETMOUSE
          rts

#endasm

/* as above noted:
 * use text screen page two line two as an intermediate jump area
 * for access to the 8-mouse firmware subroutines.
 * we use a jsr to get there from our code.
 * our jmp vector instruction is placed there based on the rom
 * configuration of the current platform.
 * because we jsr'd from our code, we will return safely to our
 * code. this is why we use a jmp to loop from our vector
 * to the firmware.
 */

mouseinit()
{
    unsigned char *vptr,*tptr;
    unsigned char temp,i;

    vptr=(unsigned char *)0xc40b; /* firmware card signature */
    temp=vptr[0];
    if(temp!=1)return;       /* this must be set to 1   */
    temp=vptr[1];            /* X Y pointing device signature */
    if(temp!=32)return;      /* this must be set to $20 */

    vptr=(unsigned char *)0xc411; /* start of mouse vectors */
    mouseflag=vptr[0];            /* this must be set to 0  */
    if(mouseflag)return;

    tptr=(unsigned char *)0x880;  /* base address - page 2 line 2 */

    for(i=0;i<8;i++)
    {
      *vptr++;
      temp=*vptr;
      *tptr= '\x4c';   /* raw jmp instruction     */
      *tptr++;
      *tptr= temp  ;   /* mouse subroutine offset */
      *tptr++;
      *tptr= '\xc4';   /* base of mouse routines  */
      *tptr++;
    }

}

/* this version of play breaks on a keypress */
int keyplay(song)
char *song;
{

    char octave, note, duration;
    int ctr=0, ret = 0, c = 0;

    /* clear stragglers from the keyboard buffer */
    while (kbhit())kbclear();

    while( (octave=song[ctr++])!=255)
    {
      note=song[ctr++];
      duration=song[ctr++];
      if (duration > 0) {
		  sound(octave,note,duration);

          c = kbhit();

          if (c != 0) {
			  ret = c;
			  break;
		  }
	  }
    }

    /* clear stragglers from the keyboard buffer */
	while (kbhit())kbclear();


return ret;

}